package com.seven.smartsnmp.discover.service;

import com.seven.smartsnmp.snmp.SNMPFactory;
import com.seven.smartsnmp.snmp.SNMPTarget;
import com.seven.smartsnmp.discover.DeviceInfo;
import com.seven.smartsnmp.discover.PortInfo;
import com.seven.smartsnmp.utils.SNMPUtils;
import com.seven.smartsnmp.mib.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import java.net.InetAddress;
import java.util.*;

public class SearchBasicDeviceInfoService {
    public SearchBasicDeviceInfoService() {
    }

    private static final Logger log = Logger.getLogger(SearchBasicDeviceInfoService.class);

    /**
     * 获取设备基本类型
     *
     * @param ip          设备ip
     * @param snmpTargets
     * @param isUsePing   是否使用ping
     * @return
     */
    public DeviceInfo getDeviceBasicInfo(String ip, List<SNMPTarget> snmpTargets, boolean isUsePing) {
        DeviceInfo deviceInfo = new DeviceInfo();
        try {
            MibSystem mibSystem = null;
            SNMPTarget snmpTarget = new SNMPTarget();
            Iterator iterator = snmpTargets.iterator();
            while (iterator.hasNext()) {
                SNMPTarget target = (SNMPTarget) iterator.next();
                snmpTarget.nodeIP = ip;
                snmpTarget.port = target.port;
                snmpTarget.readCommunity = target.readCommunity;
                snmpTarget.snmpVersion = target.snmpVersion;
                try {
                    //检查支持snmp协议
                    boolean flag = SNMPFactory.getSNMPAPI().checkSnmpAgentActive(snmpTarget);
                    if (flag) {
                        mibSystem = (MibSystem) SNMPFactory.getSNMPAPI().getMibObject(new MibSystem(), snmpTarget);
                        System.out.println("发现SNMP设备:" + ip);
                        deviceInfo.setDeviceDesc(mibSystem.getSysDescr());
                        deviceInfo.setDeviceIP(ip);
                        deviceInfo.setDeviceName(mibSystem.getSysName());
                        deviceInfo.setDeviceProtocol("SNMP");
                        deviceInfo.setDeviceSysOID(mibSystem.getSysObjectID());
                        deviceInfo.setSnmpTarget(snmpTarget);
                        this.getMainMAC(deviceInfo);
                        //本地端口接口表
                        this.getInterfaceInfo(deviceInfo);
                        // 本机对应的c
                        this.getMacIPInfo(deviceInfo);
                        this.getDocFPTableInfo(deviceInfo);
                        //lldp协议相关
                        this.getLLDPTableInfo(deviceInfo);
                        //osfp协议相关
                        this.getOSFPTableInfo(deviceInfo);
                        //cdp协议相关
                        this.getCdpCacheTable(deviceInfo);
                        //获取路由表
                        this.getRouterTable(deviceInfo);
                    }
                } catch (Exception e) {
                    System.out.println("设备:" + ip + "密码:" + snmpTarget.getReadCommunity() + e.getMessage());
                }
            }
            if (isUsePing && SNMPUtils.canPing(ip)) {
                System.out.println("发现PING设备:" + ip);
                InetAddress address = InetAddress.getByName(ip);
                String hostName = address.getCanonicalHostName();
                deviceInfo.setDeviceIP(ip);
                if (StringUtils.isNotBlank(hostName)) {
                    deviceInfo.setDeviceName(hostName);
                } else {
                    deviceInfo.setDeviceName("未知名称设备");
                }
                deviceInfo.setDeviceProtocol("Ping");
                return deviceInfo;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取设备的mac mac地址
     *
     * @param deviceInfo
     */
    private void getMainMAC(DeviceInfo deviceInfo) {
        try {
            String mac = SNMPFactory.getSNMPAPI().getOIDValue("1.3.6.1.2.1.17.1.1.0", deviceInfo.getSnmpTarget());
            if (StringUtils.isNotBlank(mac)) {
                mac = SNMPUtils.formatDispayMacAddress(mac);
                deviceInfo.setDeviceMAC(mac);
            } else {
                log.info("设备" + deviceInfo.getDeviceIP() + "未发现mac地址");
            }
        } catch (Exception e) {
            log.error("获取" + deviceInfo.getDeviceIP() + "主MAC信息出错:" + e.getMessage());
        }
    }

    /**
     * 获取机器网络接口 mac
     *
     * @param deviceInfo
     */
    private void getInterfaceInfo(DeviceInfo deviceInfo) {
        try {
            List mibIfList = SNMPFactory.getSNMPAPI().getAllTableData(MibIfEntry.class, deviceInfo.getSnmpTarget());
            Iterator iterator = mibIfList.iterator();
            while (iterator.hasNext()) {
                MibIfEntry mibIfEntry = (MibIfEntry) iterator.next();
                String address = mibIfEntry.getIfPhysAddress();
                address = SNMPUtils.formatDispayMacAddress(address);
                mibIfEntry.setIfPhysAddress(address);
                deviceInfo.getIfTableList().add(mibIfEntry);
                if (StringUtils.isNotBlank(address) && !deviceInfo.getDeviceMacList().contains(address)) {
                    deviceInfo.getDeviceMacList().add(address);
                }
            }
        } catch (Exception e) {
            System.out.println("获取:" + deviceInfo.getDeviceIP() + "接口表出错:" + e.getMessage());
        }

    }

    /**
     * ip地址转换表 ip和mac的对应关系
     * arp 表
     *
     * @param
     */
    private void getMacIPInfo(DeviceInfo deviceInfo) {
        try {
            List macIpList = SNMPFactory.getSNMPAPI().getAllTableData(MibMacIP.class, deviceInfo.getSnmpTarget());
            Iterator iterator = macIpList.iterator();
            while (iterator.hasNext()) {
                MibMacIP mibMacIP = (MibMacIP) iterator.next();
                if (mibMacIP.getIpNetToMediaType() != 2) {
                    String macAddress = SNMPUtils.formatDispayMacAddress(mibMacIP.getIpNetToMediaPhysAddress());
                    mibMacIP.setIpNetToMediaPhysAddress(macAddress);
                    if (StringUtils.isNotBlank(macAddress)) {
                        deviceInfo.getMibMacIPList().add(mibMacIP);
                    }
                }
            }
        } catch (Exception e) {
            System.out.println("获取" + deviceInfo.getDeviceIP() + "MAC-IP表出错:" + e.getMessage());
        }

    }

    /**
     * 交换机网桥信息
     *
     * @param deviceInfo
     */
    private void getDocFPTableInfo(DeviceInfo deviceInfo) {
        try {
            ///MAC Address
            List macList = SNMPFactory.getSNMPAPI().getAllTableData(Dot1dTpFdbEntry.class, deviceInfo.getSnmpTarget());
            //端口基本信息
            List basePorts = SNMPFactory.getSNMPAPI().getAllTableData(Dot1dBasePortEntry.class, deviceInfo.getSnmpTarget());
            deviceInfo.setBasePortList(basePorts);
            Iterator iterator = macList.iterator();
            while (iterator.hasNext()) {
                Dot1dTpFdbEntry dot1dTpFdbEntry = (Dot1dTpFdbEntry) iterator.next();
                String mac = dot1dTpFdbEntry.getDot1dTpFdbAddress();
                String fMac = SNMPUtils.formatDispayMacAddress(mac);
                dot1dTpFdbEntry.setDot1dTpFdbAddress(fMac);
            }
            boolean isUse = false;
            if (macList.size() <= 0) {
                isUse = true;
                Iterator macIpIt = deviceInfo.getMibMacIPList().iterator();
                while (macIpIt.hasNext()) {
                    MibMacIP macIP = (MibMacIP) macIpIt.next();
                    Dot1dTpFdbEntry dot1dTpFdbEntry = new Dot1dTpFdbEntry();
                    dot1dTpFdbEntry.setDot1dTpFdbAddress(macIP.getIpNetToMediaPhysAddress());
                    dot1dTpFdbEntry.setDot1dTpFdbPort(macIP.getIpNetToMediaIfIndex());
                    //对端
                    dot1dTpFdbEntry.setDot1dTpFdbStatus(3);
                    //2表示无效
                    if (macIP.getIpNetToMediaType() != 2) {
                        macList.add(dot1dTpFdbEntry);
                    }
                }
            }
            HashMap portMacMap = new HashMap();
            Iterator it = macList.iterator();
            while (it.hasNext()) {
                Dot1dTpFdbEntry dot1dTpFdbEntry = (Dot1dTpFdbEntry) it.next();
                if (dot1dTpFdbEntry.getDot1dTpFdbStatus() != 2 && dot1dTpFdbEntry.getDot1dTpFdbStatus() != 4) {
                    String macAddress = dot1dTpFdbEntry.getDot1dTpFdbAddress();
                    deviceInfo.getdTpFdbTableList().add(dot1dTpFdbEntry);
                    List macs = (List) portMacMap.get(dot1dTpFdbEntry.getDot1dTpFdbPort());
                    if (macs == null) {
                        macs = new ArrayList();
                        portMacMap.put(dot1dTpFdbEntry.getDot1dTpFdbPort(), macs);
                    }
                    if (StringUtils.isNotBlank(macAddress) && !((List) macs).contains(macAddress)) {
                        macs.add(macAddress);
                    }
                }
            }

            Set set = portMacMap.entrySet();
            Iterator portMacIt = set.iterator();
            while (portMacIt.hasNext()) {
                Map.Entry entry = (Map.Entry) portMacIt.next();
                PortInfo portInfo = new PortInfo();
                portInfo.device = deviceInfo;
                portInfo.port = (Integer) entry.getKey();
                portInfo.isUseIfIndexPort = isUse;
                portInfo.portMacList = (List) entry.getValue();
                deviceInfo.getPortInfoList().add(portInfo);
            }
        } catch (Exception e) {
            System.out.println("获取" + deviceInfo.getDeviceIP() + "端口转发表出错:" + e.getMessage());
        }

    }

    /**
     * 获取lldp数据出错
     *
     * @param deviceInfo
     */
    private void getLLDPTableInfo(DeviceInfo deviceInfo) {
        try {
            List<LldpLocPortEntry> locPortList = SNMPFactory.getSNMPAPI().getAllTableData(LldpLocPortEntry.class, deviceInfo.getSnmpTarget());
            List<LldpRemEntry> remList = SNMPFactory.getSNMPAPI().getAllTableData(LldpRemEntry.class, deviceInfo.getSnmpTarget());
            deviceInfo.setLldpRemTableList(remList);
            deviceInfo.setLocPortTableList(locPortList);
        } catch (Exception e) {
            System.out.println("获取" + deviceInfo.getDeviceIP() + "LLDP数据出错:" + e.getMessage());
        }
    }

    /**
     * osfp
     *
     * @param deviceInfo
     */
    private void getOSFPTableInfo(DeviceInfo deviceInfo) {
        try {
            List<OspfNbrEntry> fnbrList = SNMPFactory.getSNMPAPI().getAllTableData(OspfNbrEntry.class, deviceInfo.getSnmpTarget());
            List<OspfStubAreaEntry> areaist = SNMPFactory.getSNMPAPI().getAllTableData(OspfStubAreaEntry.class, deviceInfo.getSnmpTarget());
            deviceInfo.setOspfNbrTableList(fnbrList);
            deviceInfo.setOspfStubAreaEntryList(areaist);
        } catch (Exception e) {
            System.out.println("获取" + deviceInfo.getDeviceIP() + "OSFP数据出错:" + e.getMessage());
        }
    }

    /**
     * cdp表
     *
     * @param deviceInfo
     */
    private void getCdpCacheTable(DeviceInfo deviceInfo) {
        try {
            String value = SNMPFactory.getSNMPAPI().getOIDValue("1.3.6.1.2.1.1.2.0", deviceInfo.getSnmpTarget());
            if (StringUtils.isNotBlank(value) && value.contains("1.3.6.1.4.1.9.9")) {
                List<CdpCacheEntry> cacheEntryList = SNMPFactory.getSNMPAPI().getAllTableData(CdpCacheEntry.class, deviceInfo.getSnmpTarget());
                deviceInfo.setCdpCacheTableList(cacheEntryList);
                System.out.println("发现思科设备");
            }
        } catch (Exception e) {
            System.out.println("获取" + deviceInfo.getDeviceIP() + "cdp数据出错:" + e.getMessage());
        }
    }

    /**
     * 获取路由表
     *
     * @param deviceInfo
     */
    private void getRouterTable(DeviceInfo deviceInfo) {
        try {
            //获取路由表
            List<MibIPRouterEntry> cacheEntryList = SNMPFactory.getSNMPAPI().getAllTableData(MibIPRouterEntry.class, deviceInfo.getSnmpTarget());
        } catch (
                Exception e) {
            System.out.println("获取" + deviceInfo.getDeviceIP() + "路由表:" + e.getMessage());
        }
    }

}
